package com.molichuxing.services.business.service.impl;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.services.business.convertor.Convert;
import com.molichuxing.services.business.dto.request.create.OrderExclusivelCreateBizDto;
import com.molichuxing.services.business.dto.request.modify.OrderModifyBizDto;
import com.molichuxing.services.business.dto.request.modify.OrderPayModifyBizDto;
import com.molichuxing.services.business.dto.response.*;
import com.molichuxing.services.business.service.OrderExclusivelBizService;
import com.molichuxing.services.business.service.OrderRenegeBizService;
import com.molichuxing.services.contants.OrderStatusConst;
import com.molichuxing.services.exception.OrderExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.request.create.OrderCreateDto;
import com.molichuxing.services.infrastructure.dto.response.*;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.*;
import com.molichuxing.services.utils.OrderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 专属里程订单组合服务
 *
 * @author zoumingyu
 * @date 2019年8月12日
 */
@Service("orderExclusivelBizService")
public class OrderExclusivelBizServiceImpl implements OrderExclusivelBizService {
    private static final Logger logger = LoggerFactory.getLogger(OrderExclusivelBizServiceImpl.class);

    @Resource
    private OrderExclusivelService orderExclusivelService;

    @Resource
    private OrderScheduleService orderScheduleService;

    @Resource
    private OrderDeliveryService orderDeliveryService;

    @Resource
    private OrderReturnService orderReturnService;

    @Resource
    private OrderService orderService;

    @Resource
    private OrderStatusFlowService orderStatusFlowService;

    @Resource
    private OrderRenegeService orderRenegeService;

    @Resource
    private OrderRenegeBizService orderRenegeBizService;

    /**
     * 分页获取专属里程订单信息
     *
     * @param params   listType：列表类型-enum <br/>
     *                 orderStatus：订单状态-enum <br/>
     *                 orderCode：订单号-long <br/>
     *                 userIds：用户id-list <br/>
     *                 storeIds：门店id-list <br/>
     *                 orderTimeStart：下单开始时间-LocalDateTime <br/>
     *                 orderTimeEnd：下单结束时间-LocalDateTime
     * @param pageNum  页数
     * @param pageSize 每页条数
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @Override
    public Paged<OrderExclusivelBizDto> getOrderList(Map<String, Object> params, int pageNum, int pageSize)
            throws Exception {
        Paged<OrderExclusivelBizDto> result = null;

        // 统计每种状态下的数据量
        List<TabDto> tabs = null;
        Integer source = ObjectCastUtil.castInteger(params.get("source"));
        OrderListTypeEnum orderListType = ObjectCastUtil.castEmun(params.get("listType"), OrderListTypeEnum.class);
        if (source != null && source == 2) {
            tabs = orderExclusivelService
                    .getStatusStatistics(orderListType, ObjectCastUtil.castList(params.get("dealerStoreIds")));
        } else {
            tabs = orderExclusivelService.getStatusStatistics(orderListType);
        }
        result = new Paged<>(new ArrayList<>(), tabs, 0, pageSize);

        // 判断是否查询退租列表
        if (OrderListTypeEnum.RENEGE_LIST.equals(orderListType)) {
            // 退租开始时间-LocalDateTime
            params.put("renegeTimeStart", ObjectCastUtil.castLocalDateTimeStart(params.get("renegeTimeStart")));
            // 退租结束时间-LocalDateTime
            params.put("renegeTimeEnd", ObjectCastUtil.castLocalDateTimeEnd(params.get("renegeTimeEnd")));

            params.put("renegeStatusList",
                    Arrays.asList(OrderRenegeStatusEnum.RENEGE.getValue(), OrderRenegeStatusEnum.COMPLETE.getValue()));
        }

        Paged<OrderExclusivelDto> orderExclusivelDtoPage = orderExclusivelService.getOrderList(params, pageNum,
                pageSize);
        if (orderExclusivelDtoPage == null) {
            return result;
        } else if (orderExclusivelDtoPage.isEmpty()) {
            return result.setTotal(orderExclusivelDtoPage.getTotal());
        }

        for (OrderExclusivelDto orderExclusivelDto : orderExclusivelDtoPage.getList()) {
            result.getList().add(this.convert(orderExclusivelDto));
        }
        result.setTotal(orderExclusivelDtoPage.getTotal());

        return result;
    }

    /**
     * 专属里程dto转换并查询退租信息
     *
     * @param orderExclusivelDto
     * @return
     */
    private OrderExclusivelBizDto convert(OrderExclusivelDto orderExclusivelDto) {
        OrderExclusivelBizDto result = Convert.toOrderExclusivelBizDto(orderExclusivelDto);
        // 查询退租信息
        OrderRenegeDto orderRenegeDto = orderRenegeService.getEffectiveRenege(orderExclusivelDto.getOrderCode());
        if (orderRenegeDto == null) {
            return result;
        }
        result.setRenegeTime(orderRenegeDto.getRenegeTime());
        return result;
    }

    /**
     * 根据用户id查询专属里程订单信息
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<UserOrderBizDto> getOrderExclusivelByUser(Integer userId) {
        return userId == null ? null
                : Convert.toUserOrderBizDtoByExclusivel(orderExclusivelService.getOrderListByUser(userId));
    }

    /**
     * 根据车辆id查询专属里程订单信息
     *
     * @param carId 车辆id
     * @return
     */
    @Override
    public List<CarOrderBizDto> getOrderExclusivelByCar(Integer carId) {
        return carId == null ? null
                : Convert.toCarOrderBizDtoByExclusivel(orderExclusivelService.getOrderListByCar(carId));
    }

    /**
     * 根据车辆id查询专属里程订单信息
     *
     * @param carId    车辆id
     * @param storeIds 门店ids
     * @return
     */
    @Override
    public List<CarOrderBizDto> getOrderExclusivelByCar(Integer carId, List<Integer> storeIds) {
        return carId == null ? null
                : Convert.toCarOrderBizDtoByExclusivel(orderExclusivelService.getOrderListByCar(carId, storeIds));
    }

    /**
     * 根据条件查询付款周期
     *
     * @param params
     * @return
     */
    @Override
    public Map<LedgerRepaymentPeriodBizDto, String> getRepaymentPeriod(List<LedgerRepaymentPeriodBizDto> params) {
        Map<LedgerRepaymentPeriodBizDto, String> result = null;
        if (params == null || params.isEmpty()) {
            return result;
        }
        result = new HashMap<>();
        for (LedgerRepaymentPeriodBizDto ledgerRepaymentPeriodBizDto : params) {
            // 查询订单信息
            OrderExclusivelDto orderExclusivelDto = orderExclusivelService
                    .getOrderExclusivel(ledgerRepaymentPeriodBizDto.getOrderCode());
            if (orderExclusivelDto == null) {
                logger.error("[getRepaymentPeriod]订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() + ")对应订单不存在");
                throw new BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(),
                        "订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() + ")对应订单不存在");
            }
            // 判断付款方式
            if (OrderPaymentMethodEnum.FULL.equals(orderExclusivelDto.getPaymentMethod())) {
                // 全款
                result.put(ledgerRepaymentPeriodBizDto, orderExclusivelDto.getPaymentMethod().getName());
            } else if (OrderPaymentMethodEnum.INSTALLMENT.equals(orderExclusivelDto.getPaymentMethod())) {
                Integer scheduleId = ledgerRepaymentPeriodBizDto.getScheduleId();
                if (scheduleId != null && scheduleId == 0) {
                    List<OrderScheduleDto> orderScheduleDtoList = orderScheduleService.getOrderSchedule(ledgerRepaymentPeriodBizDto.getOrderCode());
                    if (null == orderScheduleDtoList || orderScheduleDtoList.size() < 1) {
                        logger.error("[getRepaymentPeriod]订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() + ")和排期id("
                                + ledgerRepaymentPeriodBizDto.getScheduleId() + ")对应排期信息不存在");
                        continue;
                        // throw new
                        // BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(),
                        // "订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() +
                        // ")和排期id("
                        // + ledgerRepaymentPeriodBizDto.getScheduleId() +
                        // ")对应排期信息不存在");
                    }
                    OrderScheduleDto orderScheduleDto = orderScheduleDtoList.get(0);
                    result.put(ledgerRepaymentPeriodBizDto,
                            "1/" + orderScheduleDto.getTotalPeriods());
                } else {
                    // 分期，查询排期信息
                    OrderScheduleDto orderScheduleDto = orderScheduleService
                            .getOrderSchedule(scheduleId);

                    // 排期不存在或排期对应订单号不对
                    if (orderScheduleDto == null
                            || !orderScheduleDto.getOrderCode().equals(orderExclusivelDto.getOrderCode())) {
                        logger.error("[getRepaymentPeriod]订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() + ")和排期id("
                                + ledgerRepaymentPeriodBizDto.getScheduleId() + ")对应排期信息不存在");
                        continue;
                        // throw new
                        // BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(),
                        // "订单号(" + ledgerRepaymentPeriodBizDto.getOrderCode() +
                        // ")和排期id("
                        // + ledgerRepaymentPeriodBizDto.getScheduleId() +
                        // ")对应排期信息不存在");
                    }

                    result.put(ledgerRepaymentPeriodBizDto,
                            orderScheduleDto.getPeriods() + "/" + orderScheduleDto.getTotalPeriods());
                }
            }
        }

        return result;
    }

    @Override
    public List<OrderCarInfoAppDto> getOrderExclusivelCarIdByUser(Integer userId, Integer orderStatus) {
        return orderExclusivelService.getUseCarIdByUser(userId, orderStatus);
    }

    /**
     * 订阅里程订单详情信息（包涵交车、还车等相关信息）
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderExclusivelDetailsBizDto getOrderExclusivelDetails(Long orderCode) {
        OrderExclusivelDetailsBizDto result = null;
        OrderExclusivelDto orderExclusivelDto = orderExclusivelService.getOrderExclusivel(orderCode);
        if (orderExclusivelDto == null) {
            return null;
        }
        result = Convert.toOrderExclusivelDetailsBizDto(orderExclusivelDto);

        if (OrderStatusConst.RENEGE_EXCLUSIVEL_STATUS.contains(orderExclusivelDto.getOrderStatus())) {
            // 查询退租信息
            result.setRenege(orderRenegeBizService.getOrderRenege(orderExclusivelDto.getOrderCode(),
                    orderExclusivelDto.getUserId()));
        }

        // 查询交车信息
        OrderDeliveryDto orderDeliveryDto = orderDeliveryService.getOrderDelivery(orderCode);
        if (orderDeliveryDto == null) {
            // 未交车
            return result;
        }
        result.setDeliveryd(Convert.toOrderDeliveryBizDto(orderDeliveryDto));

        // 查询还车信息
        OrderReturnDto orderReturnDto = orderReturnService.getOrderReturn(orderCode);
        if (orderReturnDto == null) {
            // 未还车
            return result;
        }
        result.setReturnd(Convert.toOrderReturnBizDto(orderReturnDto));

        return result;
    }

    /**
     * 新增专属里程订单
     *
     * @param createDto
     * @return 订单号
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Long createOrderExclusivel(OrderExclusivelCreateBizDto createDto) {
        // 订单号
        Long orderCode = OrderUtil.getOrderCode();
        // 新增订单表信息
        orderService.create(new OrderCreateDto(orderCode, OrderTypeEnum.EXCLUSIVEL));
        // 新增专属里程订单
        orderExclusivelService.create(Convert.toOrderExclusivelCreateDto(orderCode, createDto));
        // 新增订单流转信息
        orderStatusFlowService.createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(orderCode, createDto));

        return orderCode;
    }

    /**
     * 订单状态修改
     *
     * @param modifyDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyExclusivelStatus(OrderModifyBizDto modifyDto) {
        // 修改订单状态
        if (!orderExclusivelService.modify(modifyDto.getOrderCode(),
                (OrderExclusivelStatusEnum) modifyDto.getPreOrderStatus(),
                (OrderExclusivelStatusEnum) modifyDto.getOrderStatus())) {
            logger.error("[modifyExclusivelStatus]订单({})状态修改失败", modifyDto.getOrderCode());
            return false;
        }
        // 新增订单流转信息
        orderStatusFlowService
                .createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(modifyDto, OrderTypeEnum.EXCLUSIVEL));
        return true;
    }

    /**
     * 查询订单信息，并根据状态判断
     *
     * @param orderCode
     * @param orderStatus
     * @return
     */
    private OrderExclusivelDto getModify(Long orderCode, OrderExclusivelStatusEnum orderStatus) {
        return getModify(orderCode, Arrays.asList(orderStatus));
    }

    private OrderExclusivelDto getModify(Long orderCode, List<OrderExclusivelStatusEnum> orderStatusList) {
        // 查询订单信息
        OrderExclusivelDto orderExclusivelDto = orderExclusivelService.getOrderExclusivel(orderCode);
        if (orderExclusivelDto == null) {
            logger.error("[getModify]修改专属订单信息异常，订单({})不存在", orderCode);
            throw new BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(), "订单号(" + orderCode + ")对应订单不存在");
        } else if (!orderStatusList.contains(orderExclusivelDto.getOrderStatus())) {
            StringBuffer sb = new StringBuffer();
            for (OrderExclusivelStatusEnum orderExclusivelStatusEnum : orderStatusList) {
                sb.append(orderExclusivelStatusEnum.getName() + " ");
            }
            logger.error("[getModify]修改订阅订单信息异常，订单({}:{})不状态({})不为{}", orderExclusivelDto.getOrderCode(),
                    orderExclusivelDto.getOrderStatus().getValue(), orderExclusivelDto.getOrderStatus().getName(),
                    sb.toString());
            throw new BizException(OrderExceptionCodeEnum.STATUS_ERROR.getCode(),
                    "修改订单异常，订单(" + orderExclusivelDto.getOrderCode() + ")状态("
                            + orderExclusivelDto.getOrderStatus().getName() + ")不为待支付");
        }

        return orderExclusivelDto;
    }

    /**
     * 支付成功后修改订单信息
     *
     * @param modifyDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyPaySuccess(OrderPayModifyBizDto modifyDto) {
        // 查询订单信息
        OrderExclusivelDto orderExclusivelDto = getModify(modifyDto.getOrderCode(),
                Arrays.asList(OrderExclusivelStatusEnum.TRADE_UNPAID, OrderExclusivelStatusEnum.TRADE_CANCELED));
        // 修改订单信息
        OrderExclusivelStatusEnum status = null;
        if (OrderExclusivelTypeEnum.TYPE_TWO.equals(orderExclusivelDto.getType())) {
            // 订悦订单
            status = OrderExclusivelStatusEnum.TRADE_UNDELIVERY;
        } else if (OrderPaymentMethodEnum.FULL.equals(orderExclusivelDto.getPaymentMethod())) {
            // 全款订单
            status = OrderExclusivelStatusEnum.TRADE_UNDELIVERY;
        } else if (OrderPaymentMethodEnum.INSTALLMENT.equals(orderExclusivelDto.getPaymentMethod())) {
            // 分期订单，需要审核
            status = OrderExclusivelStatusEnum.TRADE_UNAUDIT;
        }
        // 计算提车截止日
        LocalDateTime deliveryDeadline = DateUtil.getDayEnd(DateUtil.plus(modifyDto.getPayTime(), 15, ChronoUnit.DAYS));
        if (!orderExclusivelService.modifyPay(
                Convert.toOrderPayModifyDto(modifyDto, status, orderExclusivelDto.getTransportTime(),
                        deliveryDeadline))) {
            return false;
        }
        // 新增排期信息
        orderScheduleService
                .createUserOrderSchedule(Convert.toOrderScheduleUserCreateDto(modifyDto, orderExclusivelDto));
        // 新增流转信息
        orderStatusFlowService.createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(modifyDto, status));

        return true;
    }
}
